package org.baojie.raft.util.current;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;

public class RaftUnsafe {

    private final static Logger log = LoggerFactory.getLogger(RaftUnsafe.class);

    private static final String Unsafe_Object_Name = "theUnsafe";

    private RaftUnsafe() {

    }

    public static Unsafe getUnsafe() {
        final Unsafe unsafe = getUnsafeInner();
        if (unsafe == null) {
            throw new NullPointerException("unsafe must not be null");
        } else {
            return unsafe;
        }
    }

    private static Unsafe getUnsafeInner() {
        Unsafe unsafe = null;
        try {
            unsafe = AccessController.doPrivileged(action);
        } catch (PrivilegedActionException e) {
            log.error("error=" + e.getMessage(), e);
        } catch (Throwable e) {
            log.error("error=" + e.getMessage(), e);
        }
        return unsafe;
    }

    private static final PrivilegedExceptionAction<Unsafe> action = new PrivilegedExceptionAction<Unsafe>() {
        @Override
        public Unsafe run() throws Exception {
            final Field theUnsafeField = makeField();
            return makeUnsafe(theUnsafeField);
        }
    };

    private static Field makeField() {
        Field field = null;
        try {
            field = Unsafe.class.getDeclaredField(Unsafe_Object_Name);
            field.setAccessible(true);
        } catch (final NoSuchFieldException e) {
            log.error("error=" + e.getMessage(), e);
        } catch (final SecurityException e) {
            log.error("error=" + e.getMessage(), e);
        } catch (Throwable e) {
            log.error("error=" + e.getMessage(), e);
        }
        if (null == field) {
            throw new NullPointerException("field get from unsafe must not be null");
        } else {
            return field;
        }
    }

    private static Unsafe makeUnsafe(final Field field) {
        Unsafe unsafe = null;
        try {
            unsafe = (Unsafe) field.get(null);
        } catch (final IllegalArgumentException e) {
            log.error("error=" + e.getMessage(), e);
        } catch (final IllegalAccessException e) {
            log.error("error=" + e.getMessage(), e);
        } catch (Throwable e) {
            log.error("error=" + e.getMessage(), e);
        }
        if (null == unsafe) {
            throw new NullPointerException("unsafe must not be null");
        } else {
            return unsafe;
        }
    }

}
